home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
src
/
das
/
passc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
7KB
|
259 lines
/*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
/*
* PASSC.C
*
* OPTIMIZATION PASS. Note that the machine list can be sent to PASSG
* without further modification whether or not this pass is run. This
* pass does simple optimization (-O1):
*
* (1) remove MOVEM instructions of REG equates for 0 registers
*
* (2) convert MOVEM instructions of REG equates for 1 register to MOVE
*
* (3) convert Bcc l1 .. l1 Bra L2 to Bcc l2 (note that if a short
* branch is forced the opt will not occur if l2 is out of range)
*
* (4) check sizes branches, set size (b,w) for unsized branches
* (this is ok because our optimizations never make the code
* larger than it currently is)
*
* (5) convert JSR x(pc) into a BSR x(pc) if it can be reduced to a byte
* offset.
*
* note that link/unlk removal is not done in this pass, but in the
* full opt pass because removal of link/unlk kills debugging.
*
* WARNING: forward offsets for labels not correct since we modify
* instructions, but can be considered a worst case range.
*
* WARNING: when using GetOpByName() remember that there may be
* sequential opcodes with the same name and different
* formats.
*/
#include "defs.h"
Prototype void PassC(void);
void
PassC()
{
MachCtx **pmc;
MachCtx *mc;
OpCod *oc;
long i;
long addr = 0;
long lost = 0; /* # bytes of code *deleted* so far */
MachCtx *lsb = NULL;
EffAddr *ea;
pmc = MBase;
for (i = 0; i < MLines; ++i, ++pmc) {
mc = *pmc;
LineNo = mc->LineNo;
if (mc->Label) {
if (lsb && mc->Label == lsb->Oper1.Label1 && addr == lsb->m_Addr + 2 && lsb->Oper1.Mode1 == AB_BBRANCH && lsb->OpCode->Id != OpBSR) {
/*
* branch to next location... backup, delete it, continue on (handles multiple deletes)
*/
if (Verbose)
cerror(EVERBOSE_REMOVED_BRANCH_NEXT);
while (i >= 0 && lsb != *pmc) {
--i;
--pmc;
}
if (i < 0)
cerror(ESOFT_BRANCH_OPT);
lsb->OpCode = NULL;
addr = lsb->m_Addr;
lost += 2;
/*
* find previous inst.. if a branch set lsb to that.
* Ignore DEBUG pseudoops which do not insert any code
*/
{
MachCtx **ppmc = pmc;
long ii = i;
while (i >= 0 && ((*ppmc)->OpCode == NULL || (*ppmc)->OpCode->Id == OdDEBUG)) {
--ii;
--ppmc;
}
if (ii >= 0)
lsb = *ppmc;
}
continue;
}
mc->Label->l_Offset = addr;
}
mc->m_Addr = addr;
if ((oc = mc->OpCode) == NULL)
continue;
if (oc->Id < 0) {
addr = ExecOpCodeC(mc, addr);
continue;
}
switch(oc->Id) {
case OpMOVEM: /* MOVEM optimization */
if (mc->Oper1.Mode1 == AB_REGS)
ea = &mc->Oper1;
else
ea = &mc->Oper2;
if (ea->Label1 && ea->Label1->l_Type == LT_REG) {
if (ea->ExtWord == 0) {
mc->OpCode = NULL; /* delete inst */
lost += 4;
continue;
}
if (ea->Reg1 >= 0) { /* just one reg.. -> MOVE */
if (ea->ExtWord & ~(1 << ea->Reg1))
cerror(ESOFT_BAD_MASK_REG, ea->Reg1, ea->ExtWord);
mc->OpCode = oc = GetOpByName("MOVE");
if (ea->Reg1 >= RB_AREG) {
if (ea == &mc->Oper2)
mc->OpCode = oc = GetOpByName("MOVEA");
ea->Mode1 = AB_AN;
} else {
ea->Mode1 = AB_DN;
}
lost += 2;
ea->Label1 = NULL;
}
}
break;
case OpJSR: /* JSR optimization */
/*
* convert a pc-relative JSR to BSR.W (easy to do since no
* change in instruction size)
*/
if (mc->Oper1.Mode1 != AB_OFFPC)
break;
oc -= 2;
mc->OpCode = oc;
mc->Oper1.Mode1 = AB_WBRANCH;
mc->OpSize = 0;
/* fall through */
case OpBCC: /* BRANCH optimization */
case OpBCS:
case OpBEQ:
case OpBGE:
case OpBGT:
case OpBHI:
case OpBLE:
case OpBLS:
case OpBLT:
case OpBMI:
case OpBNE:
case OpBPL:
case OpBVC:
case OpBVS:
case OpBRA:
case OpBSR:
if (mc->Oper1.Offset1 == 0) {
Label *lab;
long cnt = 20; /* handle loops */
while ((lab = mc->Oper1.Label1) && lab->l_Type == LT_LOC && lab->Sect == CurSection && cnt--) {
MachCtx **ppmc = lab->MC;
MachCtx *xmc;
while (*ppmc && (*ppmc)->OpCode == NULL) /* skip nothings */
++ppmc;
if ((xmc = *ppmc) == NULL) /* end of assembly */
break;
if (xmc->Sect == CurSection && xmc->OpCode->Id == OpBRA) { /* branch to branch */
if (mc == xmc) /* bra to self.. */
break;
mc->Oper1.Label1 = xmc->Oper1.Label1;
if (Verbose)
cerror(EVERBOSE_BRANCH_BRANCH);
continue;
}
/*
* mc label is local.
* (1) remove branch entirely if it
* branches to the next loc... (actually done
* at top of loop)
*
* (2) optimize to byte branch if poss. note: will not
* know about bra-to-next-addr until later.
*
*
* When optimizing branches we must take into account
* the difference in PC and actual PC.. the 'lost'
* variable, due to removing previous instructions and
* the l_Offset's of later ones being wrong by 'lost'
* bytes.
*/
if (mc->OpSize == 0) {
long range = mc->Oper1.Label1->l_Offset - (addr + 2);
if (mc->Oper1.Label1->l_Offset > (addr + 2))
range -= lost;
/*
* hack hack hack. need to convert to byte
* branch for instruction deletion but can't
* delete BSR's so must be sure we do not convert
* to a BSR to the next instruction
*/
if (range >= -126 && range < 126 && range) {
if (oc->SModes & AF_WBRANCH) {
if (range != 2 || oc->Id != OpBSR) {
mc->OpCode = ++oc;
mc->Oper1.Mode1 = AB_BBRANCH;
lost += 2;
}
}
} else {
if (oc->SModes & AF_BBRANCH) {
mc->OpCode = --oc;
mc->Oper1.Mode1 = AB_WBRANCH;
lost -= 2;
}
}
lsb = mc;
}
break;
}
}
break;
case OpLINK:
if (Optimize >= 1) {
if ((GetFlags() & ~MF_CALLMADE) == 0 && mc->Oper1.Label1 == NULL && mc->Oper1.Offset1 == 0) {
lost += 4;
mc->OpCode = NULL; /* delete inst */
continue;
} else {
SetA5UsedFlag();
}
}
break;
case OpUNLK:
if (Optimize >= 1) {
if ((GetFlags() & ~MF_CALLMADE) == 0) {
lost += 2;
mc->OpCode = NULL;
continue;
}
}
break;
default:
lsb = NULL; /* efficiency boost, not reqd */
}
addr += GetInstSize(mc);
}
}